// 自定义参数校验方法以及错误信息

package utils

import (
	"fmt"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"reflect"
	"strings"
)

const tagName = "err"

// 自定义校验方法的tag
const (
	myDemoTag = "myDemo"
	// add more custom tag here.
)

// 字段名-tag名-对应错误信息
var fieldNameMap map[string]map[string]string

func init() {
	fieldNameMap = map[string]map[string]string{
		"name": {"required": "不能为空", "max": "长度过长", myDemoTag: "自定义的错误信息"},
	}
}

func RegisterValidatorCustomFunc() {
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		_ = v.RegisterValidation(myDemoTag, myDemo)
		// 在此处添加自定义参数校验方法
	}
}

// 自定义校验方法示例
func myDemo(f validator.FieldLevel) bool {
	value := f.Field().String()
	if value != "abc" {
		return false
	}
	return true
}

// GetValidateErr 获取自定义错误信息，通过结构体的 "err" tag获取
func GetValidateErr(obj interface{}, rawErr error) string {
	if rawErr == nil {
		return ""
	}
	if invalidErr, ok := rawErr.(*validator.InvalidValidationError); ok {
		return invalidErr.Error()
	}

	validationErrs, ok := rawErr.(validator.ValidationErrors)
	if !ok {
		return rawErr.Error()
	}
	var errString []string
	objType := reflect.TypeOf(obj)
	if objType.Kind() == reflect.Ptr {
		objType = objType.Elem()
	}
	for _, validationErr := range validationErrs {
		field, ok := objType.FieldByName(validationErr.Field())
		if ok {
			// 优先取tag中的自定义错误信息，其次取全局map中定义的自定义错误信息
			if e := field.Tag.Get(tagName); e != "" {
				errString = append(errString, fmt.Sprintf("%s: %s", validationErr.Field(), e))
			} else {
				tagNameMap, ok := fieldNameMap[validationErr.Field()]
				if ok && tagNameMap != nil {
					errMsg := tagNameMap[validationErr.Tag()]
					if errMsg != "" {
						errString = append(errString, fmt.Sprintf("%s: %s", validationErr.Field(), errMsg))
					}
				}
			}
		}
	}
	//未获取到自定义错误信息，则返回原错误
	if len(errString) == 0 {
		return rawErr.Error()
	}
	return strings.Join(errString, "\n")
}
